package com.sh.data.engine.domain.base.service.impl;

import com.google.common.collect.Lists;
import com.sh.data.engine.common.constants.HttpStatus;
import com.sh.data.engine.common.constants.code.BizCodes;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.domain.base.service.LogService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.buildobjects.process.ProcBuilder;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.sh.data.engine.common.constants.Constants.LogFileExp.*;


/**
 * @author: mengzheng.mhc
 * @date: 2024/6/19 9:43
 */
@Service
@Slf4j
public class LogServiceImpl implements LogService {

    @Override
    public void write(String filePath, List<String> lines) {
        try {
            File file = new File(filePath);

            synchronized (NFSFileServiceImpl.class) {
                if (!file.getParentFile().exists()) {
                    FileUtils.createParentDirectories(file);
                }
                if (!file.exists()) {
                    file.createNewFile();
                }

                FileUtils.writeLines(file, "UTF-8", lines, true);
            }
        } catch (IOException e) {
            log.error("写文件异常", e);
        }
    }

    @Override
    public List<String> read(String filePath, int startLine) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            throw new IllegalArgumentException("StringUtils.isBlank(filePath)");
        }

        File file = new File(filePath);
        if (!file.exists()) {
            return new ArrayList<>();
        }
        String absoluteFile = file.getAbsoluteFile().toString();
        String content = readContent(absoluteFile, startLine);
        try (StringReader reader = new StringReader(content)) {
            return IOUtils.readLines(reader);
        }
    }

    private String readLine(String file, int startLine) {
        if (startLine == 0) {
            startLine = 1;
        }
        if (StringUtils.isBlank(file)) {
            throw new IllegalArgumentException("file is null");
        }
        if (startLine <= 0) {
            throw new IllegalArgumentException("invalid startLine " + startLine);
        }
        return ProcBuilder.run("sed", "-n", startLine + ",$p", file);
    }

    @Override
    public List<String> readWithKeyWord(String filePath, String keyword) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            throw new IllegalArgumentException("StringUtils.isBlank(filePath)");
        }

        File file = new File(filePath);
        if (!file.exists()) {
            throw new BusinessException(BizCodes.LOG_FILE_NOT_EXISTS_ERROR, HttpStatus.BAD_REQUEST);
        }
        String absoluteFile = file.getAbsoluteFile().toString();
        String content = readByKeyWords(absoluteFile, keyword);
        try (StringReader reader = new StringReader(content)) {
            return IOUtils.readLines(reader);
        }
    }

    /**
     * @param filePath
     * @param startLine
     * @description : 读日志，读不到返回null
     * @author : tinglan.ys
     * @date : 2022/3/21
     */
    @Override
    public List<String> readNew(String filePath, int startLine) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }

        File file = new File(filePath);
        if (!file.exists()) {
            return null;
        }
        String absoluteFile = file.getAbsoluteFile().toString();
        String content = readContent(absoluteFile, startLine);
        try (StringReader reader = new StringReader(content)) {
            return IOUtils.readLines(reader);
        }
    }

    @Override
    public List<Map<String, Object>> readResult(
            String rsPathDir, int start, int end, List<String> hasShowd) throws IOException {
        if (StringUtils.isBlank(rsPathDir)) {
            throw new IllegalArgumentException("invalid dirPath " + rsPathDir);
        }
        List<Map<String, Object>> rss = null;
        File dir = new File(rsPathDir);
        if (null != dir) {
            rss = Lists.newArrayList();
            File[] files =
                    dir.listFiles(
                            (dir1, name) -> new File(dir1, name).isFile() && name.endsWith(RS_TMP_FILE_SUFFIX));
            if (null != files) {
                for (File file : files) {
                    String fileName = file.getName();

                    if (hasShowd.contains(fileName)) {
                        continue;
                    }
                    Map<String, Object> map = new HashMap<>();
                    String sqlFilePath =
                            file.getParent()
                                    + File.separator
                                    + fileName.substring(0, fileName.lastIndexOf("."))
                                    + SQL_FILE_SUFFIX;
                    File sqlFile = new File(sqlFilePath);
                    if (sqlFile.exists()) {
                        String sql = FileUtils.readFileToString(sqlFile, "UTF-8");
                        map.put("sql", sql);
                    }

                    String content = read(file.getAbsolutePath(), start, end);
                    try (StringReader reader = new StringReader(content)) {
                        List<String> rs = IOUtils.readLines(reader);
                        List<List<String>> result = transformData(rs);

                        map.put("result", file.getName());
                        map.put("key", file.getName());
                        map.put("value", result);

                        rss.add(map);
                    }
                }
            }
        }
        return rss;
    }

    @SneakyThrows
    @Override
    public List<List<String>> readHiveRs(String dirPath, int startLine, String fileName) {
        if (StringUtils.isBlank(dirPath)) {
            throw new IllegalArgumentException("invalid jobId " + dirPath);
        }

        File file = new File(dirPath + IOUtils.DIR_SEPARATOR + fileName);
        if (!file.exists()) {
            return Lists.newArrayList();
        }
        String content = readLine(file.getAbsolutePath(), startLine);
        try (StringReader reader = new StringReader(content)) {
            List<String> rs = IOUtils.readLines(reader);
            List<List<String>> result = transformData(rs);
            return result;
        }
    }

    private static List<List<String>> transformData(List<String> rs) {
        List<List<String>> result = Lists.newArrayList();
        for (String r : rs) {
            String[] cols = r.split(COL_SEPARATOR);
            List<String> values = Lists.newArrayList();
            for (String col : cols) {
                String val = StringEscapeUtils.unescapeJava(StringEscapeUtils.unescapeCsv(col));
                val = "\\N".equals(val) ? "" : val;
                values.add(val);
            }
            result.add(values);
        }

        return result;
    }

    private static String readByKeyWords(String file, String keywords) {

        if (StringUtils.isBlank(file)) {
            throw new IllegalArgumentException("file is null");
        }

        if (StringUtils.isBlank(keywords)) {
            throw new IllegalArgumentException("keywords is blank");
        }

        return ProcBuilder.run("sed", "-n", "/" + keywords + "/p", file);
    }

    private static String read(String file, int startLine, int endLine) {
        if (startLine == 0) {
            startLine = 1;
        }
        if (StringUtils.isBlank(file)) {
            throw new IllegalArgumentException("file is null");
        }
        if (startLine <= 0) {
            throw new IllegalArgumentException("invalid startLine " + startLine);
        }
        if (endLine <= 0) {
            throw new IllegalArgumentException("invalid endLine " + endLine);
        }
        if (endLine < startLine) {
            throw new IllegalArgumentException("endLine " + endLine + " lt startLine " + startLine);
        }
        return ProcBuilder.run("sed", "-n", startLine + "," + endLine + "p", file);
    }

    private static String readContent(String filePath, int startLine) {
        if (startLine == 0) {
            startLine = 1;
        }
        if (StringUtils.isBlank(filePath)) {
            throw new IllegalArgumentException("file is null");
        }
        if (startLine <= 0) {
            throw new IllegalArgumentException("invalid startLine " + startLine);
        }
        StringBuffer stringBuffer = new StringBuffer();

        try {
            BufferedReader in = new BufferedReader(new FileReader(filePath));
            String str;
            while ((str = in.readLine()) != null) {
                stringBuffer.append(str);
            }
        } catch (IOException e) {
        }
//        return ProcBuilder.run("sed", "-n", startLine + ",$p", filePath);
        return stringBuffer.toString();
    }
}
